#define MSPCAP_C
#include <stdio.h>
#include <libmslog/mslog.h>
#include <libmscommon/mscommon.h>
#include <libmscommon/mstime.h>
#include <libmscommon/msnetframe.h>
#include <libmscommon/msstring.h>
#include <libmscommon/mssignal.h>
#include <libmscommon/msthread.h>
#include <libmscommon/msnetwork.h>
#include <libmstool/msweb.h>
#include <libmsprotocol/msprotocol.h>
#include <libmslog/mslog.h>
#include "mspcap.h"

#define FLAG "mspcap"

ms_s08 mspacp_api_setopt_noactivated (pcap_t *handle)
{
 //set  option  for a not-yet-activated pcap_t for live capture 	 
//snapshot length
	//pcap_set_snaplen(pcap_t * p, int snaplen)
	int snaplen=pcap_snapshot(handle);
	ms_debug("snaplen:%d",snaplen);
	
//promiscuous mode
	//pcap_set_promisc(pcap_t * p, int promisc)
//monitor mode
	//pcap_set_rfmon(pcap_t * p, int rfmon)
	//pcap_can_set_rfmon

	//pcap_set_protocol_linux(pcap_t * p, int protocol)

//packet buffer timeout
	//pcap_set_timeout(pcap_t * p, int timeout_ms)
//immediate mode	
	//pcap_set_immediate_mode(pcap_t * p, int immediate)
//buffer size	
	//pcap_set_buffer_size
//timestamp type
	//pcap_set_tstamp_type(pcap_t * p, int tstamp_type)
	//pcap_list_tstamp_types(pcap_t * p, int * * tstamp_typesp)
	//pcap_free_tstamp_types
	//pcap_tstamp_type_val_to_name(int tstamp_type)
	//pcap_tstamp_type_val_to_description
	//pcap_tstamp_type_name_to_val
	//pcap_set_tstamp_precision
	int precision=pcap_get_tstamp_precision(handle);
	ms_debug("precision:%d",precision);
}
pcap_t * mspacp_api_open(ms_string pdev)
{
//list all dev
	//pcap_findalldevs(pcap_if_t * * alldevsp, char * errbuf)
	//pcap_freealldevs(pcap_if_t * alldevs)
//if no set dev,get one
	ms_debug("version:%s",pcap_lib_version());

	ms_byte errbuf[PCAP_ERRBUF_SIZE]={0};

	pcap_if_t	*network_interface_list = NULL ;
	ms_s32 nret = pcap_findalldevs( & network_interface_list , errbuf) ;
	if( nret == -1 ){
		ms_errRet(ms_null, "*** ERROR : pcap_findalldevs failed :%s" , errbuf );
	}
	pcap_if_t	*network_interface =network_interface_list ;
	if( 0!=ms_buflen(pdev) ){
		while( network_interface ){
			if( ms_strncmp_saeq( network_interface->name , pdev ) ){
				break;
			}
			network_interface = network_interface->next ;
		}
		if( network_interface == ms_null ){
			ms_errRet(ms_null, "*** ERROR : network interface [%s] not found" ,pdev );
		}
	}else{
		ms_strcpy(pdev, network_interface->name);
	}
	pcap_freealldevs( network_interface_list );
	ms_debug("Device: %s", pdev);

	//pcap_create(const char * device, char * errbuf)
	//pcap_activate(pcap_t * p)
	
	//pcap_open_offline(const char *fname, char *errbuf)
	//pcap_open_offline_with_tstamp_precision(const char * fname, u_int precision, char * errbuf)

	//pcap_fopen_offline(f, b)
	//pcap_fopen_offline_with_tstamp_precision
	
	//pcap_open_dead(int linktype, int snaplen);---------->create a ``fake'' pcap_t
	pcap_t *  handle= pcap_open_live(pdev, BUFSIZ, 1, 1000, errbuf);
	 if (handle == ms_null) {
		 ms_errRet(ms_null,  "Couldn't open device %s: %s", pdev, errbuf);
	 }
	 return handle;
}
ms_bool mspacp_api_isen10mb(pcap_t *handle)
{
	if (pcap_datalink(handle) != DLT_EN10MB) {
		 ms_errRet(ms_false, "Device doesn't provide Ethernet headers - not supported");
	}
	return ms_true;
}

ms_s08 mspacp_api_setfilter(pcap_t *handle,ms_string dev,ms_string filter_exp)
{
	 struct bpf_program fp;	
	 bpf_u_int32 net_mask;		
	 bpf_u_int32 net;
	ms_byte errbuf[PCAP_ERRBUF_SIZE]={0};
	if( pcap_lookupnet( dev , & net , & net_mask , errbuf ) == -1 ){
		ms_errRet(-1,  "pcap_lookupnet failed:%s" , errbuf );
	}
	if( ms_strncmp_saeq("none",filter_exp)){
		filter_exp= "" ;
	}
	 if (pcap_compile(handle, &fp, filter_exp, 0, net_mask) == -1) {
		ms_errRet(-1, "Couldn't parse filter %s: %s", filter_exp, pcap_geterr(handle));
	 }
	 if (pcap_setfilter(handle, &fp) == -1) {
		 ms_errRet(-1,  "Couldn't install filter %s: %s", filter_exp, pcap_geterr(handle));
	 }
	 return 0;
}
ms_void mspacp_api_close(pcap_t *handle)
{
	pcap_close(handle);
}

int mspacp_api_send(pcap_t * p, ms_byte * buf, ms_s32 size)
{
//WinPcap
	//return pcap_sendpacket(p,  buf,size)
//OpenBSD
	return pcap_inject(p,  (const ms_void *)buf,  (size_t)size);
}

pcap_dumper_t *mspacp_api_dumpopen(pcap_t * p, const char * fname, FILE *f)
{
	if(ms_null==f){
		return pcap_dump_open(p, fname);
	}else{
		return pcap_dump_fopen(p, f);
	}
}

ms_void mspacp_api_dumpwrite(FILE *f, const struct pcap_pkthdr * h, const u_char * sp)
{
	pcap_dump((u_char *) f,  h, sp);
}

FILE * mspacp_api_dumpgetfilehd(pcap_dumper_t * p)
{
	return pcap_dump_file(p);
}
long mspacp_api_dumpftell(pcap_dumper_t * p)
{
	return pcap_dump_ftell(p);
}	
//pcap_dump(u_char * user, const struct pcap_pkthdr * h, const u_char * sp);
//pcap_dump_flush(pcap_dumper_t * p)
//pcap_dump_ftell(pcap_dumper_t * p)

ms_void mspacp_api_dumpclose(pcap_dumper_t * p)
{
	if(pcap_dump_flush(p)<0){
		ms_error("pcap_dump_flush error");
	}
	pcap_dump_close(p);
}
#undef MSPCAP_C

